import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.lang.IllegalAccessException;

public class DynamicProxyExample {

	// 原接口
	interface Hello {
		void sayHi(String[] args);
	}

	// 接口实现类
	static class HelloImpl implements Hello {
		public void sayHi(String[] args) {
			System.out.println("HelloImpl:" + Arrays.toString(args));
		}
	}

	// 动态代理, 该 class对 Hello一无所知
	static class LogInvocationHandler implements InvocationHandler {
		private Object target;
		LogInvocationHandler() {}

		// 绑定一个 target, 返回一个代理对象
		Object bind(Object target) {
			this.target = target;
			return Proxy.newProxyInstance(
				target.getClass().getClassLoader(),		// 1. 类加载器
				target.getClass().getInterfaces(),		// 2. 代理需要实现的接口, 可以多个
				this 									// 3. 方法实际处理者
			);
		}

		// 第一个参数 proxy是什么
		// https://stackoverflow.com/questions/22930195/understanding-proxy-arguments-of-the-invoke-method-of-java-lang-reflect-invoca
		// proxy 可以看成 上下文一样的东西, return proxy 后可以 链式调用
		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
			System.out.println("logger before");
			Object result =  method.invoke(target, args);
			System.out.println("logger after");
			return result;
		}
	}

	// 调用
	public static void main(String[] args) throws IllegalAccessException {
		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); // 看到生成的代码，

		LogInvocationHandler proxy = new LogInvocationHandler();
		Hello hello = (Hello)proxy.bind(new HelloImpl());
		hello.sayHi(new String[] {"foo", "bar"});
	}
}